﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DynORM.Interfaces;
using DynORM.Enums;
using DynORM.DAL;
using DynORM.DAL.Interfaces;
using DynORM.ValueObjects;

namespace DynORM.Mappers
{
    public static class RowMapper
    {
        public static IDAL ChooseDAL(DBMSTypes rdbmsKind)
        {
            IDAL dal = null;
            if (rdbmsKind == DBMSTypes.MSSQL)
                dal = new DAL_MSSQL();
            else if (rdbmsKind == DBMSTypes.PostgreSQL)
                dal = new DAL_PostgreSQL();
            else if (rdbmsKind == DBMSTypes.MySQL)
                dal = new DAL_MySQL();
            else if (rdbmsKind == DBMSTypes.Oracle)
                dal = new DAL_Oracle();
            else
                throw new Exception("RDBMS type is not supported.");
            return dal;
        }

        //DML
        //select
        public static IRow RowRead(string connectionString, DBMSTypes rdbmsKind, IPrimaryKey pk)
        {
            IDAL dal = ChooseDAL(rdbmsKind);

            IRow row = dal.SelectRow(connectionString, pk);
            if (row == null) return null;

            CheckIntegrityResult cir = row.CheckValuesIntegrity(false);
            if (cir.Result == false)
                throw new Exception(cir.Reason);

            return row;
        }

        public static IEnumerable<IRow> RowsRead(string connectionString, DBMSTypes rdbmsKind, string tableName)
        {
            IDAL dal = ChooseDAL(rdbmsKind);

            IRowDescriptor rowDescriptor = dal.SelectTableStructure(connectionString, tableName);
            if (rowDescriptor == null) return null;

            CheckIntegrityResult cir = rowDescriptor.CheckStructureIntegrity(false);
            if (cir.Result == false)
                throw new Exception(cir.Reason);

            IEnumerable<IRow> rows = dal.SelectRows(connectionString, tableName);
            if (rows == null) return null;

            foreach (IRow r in rows)
            {
                cir = r.CheckOnlyValuesIntegrity(false);
                if (cir.Result == false)
                    throw new Exception(cir.Reason);
            }
            return rows;
        }

        public static IEnumerable<IRow> RowsRead(string connectionString, DBMSTypes rdbmsKind, string tableName, IEnumerable<IORMComparison> predicate)
        {
            IDAL dal = ChooseDAL(rdbmsKind);

            IRowDescriptor rowDescriptor = dal.SelectTableStructure(connectionString, tableName);
            if (rowDescriptor == null) return null;

            CheckIntegrityResult cir = rowDescriptor.CheckStructureIntegrity(false);
            if (cir.Result == false)
                throw new Exception(cir.Reason);

            IEnumerable<IRow> rows = dal.SelectRows(connectionString, tableName, predicate);
            if (rows == null) return null;

            foreach (IRow r in rows)
            {
                cir = r.CheckOnlyValuesIntegrity(false);
                if (cir.Result == false)
                    throw new Exception(cir.Reason);
            }
            return rows;
        }

        //insert
        //constract a new Row + RowWrite

        //update
        public static void RowWrite(string connectionString, DBMSTypes rdbmsKind, IRow row)
        {
            CheckIntegrityResult cir = row.CheckValuesIntegrity(false);
            if (cir.Result == false)
                throw new Exception(cir.Reason);

            IDAL dal = ChooseDAL(rdbmsKind);

            IPrimaryKey pk = (IPrimaryKey)row.Relations.First<IRelation>(r => r.RelationType == RelationType.PrimaryKey);
            if (dal.SelectRow(connectionString, pk) == null)
                dal.AddRow(connectionString, row);
            else
                dal.UpdateRow(connectionString, row);
        }

        //delete
        public static void RowDelete(string connectionString, DBMSTypes rdbmsKind, IRow row)
        {
            IDAL dal = ChooseDAL(rdbmsKind);
            dal.DeleteRow(connectionString, row);
        }

        public static void RowDelete(string connectionString, DBMSTypes rdbmsKind, IPrimaryKey pk)
        {
            IDAL dal = ChooseDAL(rdbmsKind);
            dal.DeleteRow(connectionString, pk);
        }
    }

}
